package com.mingyuan.library.infra.lending.patron.entity;


import com.mingyuan.library.domain.lending.patron.enums.PatronType;
import com.mingyuan.library.domain.lending.patron.event.*;
import com.mingyuan.library.domain.lending.patron.model.valueobject.PatronId;
import io.vavr.API;
import lombok.Data;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import static io.vavr.API.$;
import static io.vavr.API.Case;
import static io.vavr.Predicates.instanceOf;
@Data
public class PatronDatabaseEntity {


    Long id;
    UUID patronId;
    PatronType patronType;
    /**
     * 预定中的图书集合
     */
    public Set<HoldDatabaseEntity> booksOnHold;
    /**
     * 逾期借阅集合
     */
    public Set<OverdueCheckoutDatabaseEntity> checkouts;

    /**
     * 读者数据库实体信息
     * @author yangzk
     * @param patronId 读者ID
     * @param patronType 读者类型
     * @date 2023/12/28 18:58
     **/
    public PatronDatabaseEntity(PatronId patronId, PatronType patronType) {
        this.patronId = patronId.getPatronId();
        this.patronType = patronType;
        this.booksOnHold = new HashSet<>();
        this.checkouts = new HashSet<>();
    }
    /**
     * 读者借阅事件处理
     * @author yangzk
     * @param event 事件信息
     * @date 2023/12/28 19:29
     **/
    public PatronDatabaseEntity handle(PatronEvent event) {
        return API.Match(event).of(
                // 如果是图书预定事件 从预定->预定中
                Case($(instanceOf(BookPlacedOnHoldEvents.class)), this::handle),
                // 如果是预定中事件
                Case($(instanceOf(BookPlacedOnHold.class)), this::handle),
                // 如果是借阅事件
                Case($(instanceOf(BookCheckedOut.class)), this::handle),
                // 如果是 图书取消预定事件
                Case($(instanceOf(BookHoldCanceled.class)), this::handle),
                // 如果是 预定过期事件
                Case($(instanceOf(BookHoldExpired.class)), this::handle),
                // 如果是 逾期借阅登记事件
                Case($(instanceOf(OverdueCheckoutRegistered.class)), this::handle),
                // 如果是 还书事件
                Case($(instanceOf(BookReturned.class)), this::handle)

        );
    }
    /**
     * 图书预定事件处理
     * @author yangzk
     * @param placedOnHoldEvents 已预定事件
     * @date 2023/12/28 19:29
     **/
    private PatronDatabaseEntity handle(BookPlacedOnHoldEvents placedOnHoldEvents) {
        // 获取预定中图书事件
        BookPlacedOnHold event = placedOnHoldEvents.getBookPlacedOnHold();
        // 从未预定到预定中处理
        return handle(event);
    }

    /**
     * 预定中时间处理
     * @author yangzk
     * @param event 预定中事件
     * @date 2023/12/28 19:39
     **/
    private PatronDatabaseEntity handle(BookPlacedOnHold event) {
        // 添加到预定中的图书集合
        booksOnHold.add(new HoldDatabaseEntity(event.getBookId(), event.getPatronId(), event.getLibraryBranchId(), event.getHoldTill()));
        return this;
    }
    /**
     * 取消预定事件
     * @author yangzk
     * @param event 取消图书预定事件信息
     * @date 2023/12/28 19:42
     **/
    private PatronDatabaseEntity handle(BookHoldCanceled event) {
        // 从预定中集合中移除
        return removeHoldIfPresent(event.getPatronId(), event.getBookId(), event.getLibraryBranchId());
    }

    /**
     * 借阅事件处理
     * @author yangzk
     * @param event 借阅图书信息
     * @date 2023/12/28 19:46
     **/
    private PatronDatabaseEntity handle(BookCheckedOut event) {
        // 从预定中的集合中移除
        return removeHoldIfPresent(event.getPatronId(), event.getBookId(), event.getLibraryBranchId());
    }

    /**
     * 预定超期，从预定列表中移除预定记录
     * @param event
     * @return
     */
    private PatronDatabaseEntity handle(BookHoldExpired event) {
        return removeHoldIfPresent(event.getPatronId(), event.getBookId(), event.getLibraryBranchId());
    }

    private PatronDatabaseEntity handle(OverdueCheckoutRegistered event) {
        checkouts.add(new OverdueCheckoutDatabaseEntity(event.getBookId(), event.getPatronId(), event.getLibraryBranchId()));
        return this;
    }

    private PatronDatabaseEntity handle(BookReturned event) {
        return removeOverdueCheckoutIfPresent(event.getPatronId(), event.getBookId(), event.getLibraryBranchId());
    }
    /**
     * 如果存在删除预定
     * @author yangzk
     * @param patronId 读者ID
     * @param bookId 图书ID
     * @param libraryBranchId 图书馆分馆ID
     * @date 2023/12/28 19:48
     **/
    private PatronDatabaseEntity removeHoldIfPresent(UUID patronId, UUID bookId, UUID libraryBranchId) {
        booksOnHold
                .stream()
                .filter(entity -> entity.is(patronId, bookId, libraryBranchId))
                .findAny()
                .ifPresent(entity -> booksOnHold.remove(entity));
        return this;
    }

    private PatronDatabaseEntity removeOverdueCheckoutIfPresent(UUID patronId, UUID bookId, UUID libraryBranchId) {
        checkouts
                .stream()
                .filter(entity -> entity.is(patronId, bookId, libraryBranchId))
                .findAny()
                .ifPresent(entity -> checkouts.remove(entity));
        return this;
    }

}


